import { intervalToDuration, addSeconds, formatISODuration } from "date-fns";

export default function pick(setting) {
  const isObject = (some) => typeof some === "object" && some !== null;
  const isArray = (some) => some instanceof Array;
  const isString = (some) => typeof some === "string";

  function typeConvert(value, typeString, ...typeParams) {
    if (!typeString) return value;
    switch (typeString.trim().toLowerCase()) {
      case "float":
        return parseFloat(value, ...typeParams);
      case "int":
        return parseInt(value, ...typeParams);
      case "date-iso": {
        const d = new Date(value);
        return Number.isNaN(d.getTime()) ? "" : d.toISOString();
      }
      case "duration-iso-8601": {
        const duration = parseInt(value, 10);
        const start = new Date();
        const end = addSeconds(start, Number.isNaN(duration) ? 0 : duration);
        return formatISODuration(intervalToDuration({ start, end }));
      }
      default:
        return value;
    }
  }

  function deepProp(object, string) {
    const [propKey, propType, ...propTypeParams] = string.split(",");
    const props = propKey.trim().split(".");
    const value = props.reduce(
      (o, key) => (o && isObject(o) ? o[key] : o),
      object
    );
    return {
      key: props[props.length - 1],
      value: typeConvert(value, propType, ...propTypeParams),
    };
  }

  function pickArray(array) {
    return function pickArrayFunc(object) {
      return array.reduce((o, k) => {
        const { key, value } = deepProp(object, k);
        return { ...o, [key]: value };
      }, {});
    };
  }

  function pickObject(objectSetting) {
    return function pickObjectFunc(object) {
      return Object.keys(objectSetting).reduce((o, k) => {
        const { value } = deepProp(object, objectSetting[k]);
        return { ...o, [k]: value };
      }, {});
    };
  }

  if (isArray(setting)) {
    return pickArray(setting);
  }
  if (isObject(setting)) {
    return pickObject(setting);
  }
  if (isString(setting)) {
    return (obj) => deepProp(obj, setting).value;
  }

  throw new Error("参数必须为String、Object、Array类型");
}
